/*
 * DefaultBrain.java
 *
 * This work is free software; you can redistribute it and/or
 * modify it under the terms of the Apache License as published 
 * by the Apache Software Foundation.
 *
 * This work is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * Apache License for more details.
 *
 * Copyright (c) 2011 Tran Hoang Anh (tranhoanganh89@gmail.com). 
 * All rights reserved.
 */
package net.hoanganh.jbraintetris;

import java.awt.Point;

/**
 * Default implement of brain.
 */
public class DefaultBrain implements Brain {
	protected BrainMove bestMove = new BrainMove();
	protected boolean finishMove = true;

	@Override
	public void doAction(TetrisBoard board) {
		if (board == null) {
			return;
		}

		// Check if finish moving
		if (finishMove) {
			return;
		}

		// Navigate to best location
		Piece piece = board.getPiece();
		if (piece == null) {
			return;
		}
		if (piece.getOrientation() != bestMove.orientation) {
			piece.rotate();
			return;
		}
		if (board.getxPos() != bestMove.x) {
			if (bestMove.x > board.getxPos()) {
				board.moveRight();
			} else {
				board.moveLeft();
			}
			return;
		}
		if (board.getyPos() != bestMove.y) {
			board.moveAllDown();
			finishMove = true;
			return;
		}
	}

	@Override
	public void calculateBestMove(TetrisBoard board) {
		if (board == null) {
			return;
		}

		Piece piece = board.getPiece();
		if (piece == null) {
			return;
		}

		double minScore = Double.MAX_VALUE;
		for (int o = 0; o < piece.getMaxOrientation(); o++) {
			piece.rotate();
			for (int x = 0; x <= board.getBoardSize().width; x++) {
				// all square is not outside side bounds.
				if (!board.canMoveTo(x, 0)) {
					continue;
				}
				// get landed place
				int y = 0;
				while (board.canMoveTo(x, y + 1)) {
					y++;
				}
				double score = rate(board, x, y);
				if (score < minScore) {
					minScore = score;
					bestMove.x = x;
					bestMove.y = y;
					bestMove.orientation = piece.getOrientation();
				}
			}
		}

		finishMove = false;
	}

	protected double rate(TetrisBoard board, int x, int y) {
		boolean[][] matrix = getBoardMatrix(board, x, y);

		// Count holes
		int holes = 0;
		for (int i = 0; i < board.getBoardSize().width; i++) {
			for (int j = 1; j < board.getBoardSize().height; j++) {
				if (!matrix[i][j] && matrix[i][j - 1]) {
					holes++;
				}
			}
		}

		// Count height
		int maxHeight = -1;
		int sumHeight = 0;
		for (int i = 0; i < board.getBoardSize().width; i++) {
			for (int j = 1; j < board.getBoardSize().height; j++) {
				if (matrix[i][j]) {
					int height = board.getBoardSize().height - j - 1;
					sumHeight += height;
					maxHeight = Math.max(maxHeight, height);
				}
			}
		}
		int avgHeight = sumHeight / board.getBoardSize().width;

		return 8 * maxHeight + 40 * avgHeight + 20 * holes;
	}

	protected boolean[][] getBoardMatrix(TetrisBoard board, int x, int y) {
		boolean[][] result = new boolean[board.getBoardSize().width][board
				.getBoardSize().height];

		// Get existed squares in board
		for (int i = 0; i < board.getBoardSize().width; i++) {
			for (int j = 0; j < board.getBoardSize().height; j++) {
				result[i][j] = !board.isEmpty(i, j);
			}
		}

		// With squares of piece. Notes : there are some squares of piece have 
		// vertical location is less than 0 because it is when the piece is not
		// fully visible in the board so we have to check this case manually.
		Piece piece = board.getPiece();
		for (Point p : piece.getPositions()) {
			int i = p.x + x;
			int j = p.y + y;	
			if (j >= 0 && j < board.getBoardSize().height && 
					i >= 0 && i < board.getBoardSize().width) {
				result[i][j] = true;
			}
		}

		return result;
	}

	@Override
	public void configure() {
		finishMove = true;
	}
}
